﻿using System;
using System.ComponentModel.Design;
using SedionFormDesigner.Infrastructure;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;

namespace SedionFormDesigner.Service
{
    /// <summary>
    ///  用来控制设计器组件选中项
    /// </summary>
    internal class SedionSelectionService : ISelectionService
    {
        private IDesignerHost host;
        // 主选择对象
        private SelectionItem primarySelection;
        // 选择到的对象的哈希表
        private Hashtable selectionsByComponent;
        // 属性过滤
        private static PropertyFilter filter;


        // 是否在批(batch)状态
        private Boolean batchMode;
        // 如果在batch Mode 下选中项改变了则为true
        private Boolean selectionChanged;
        // 如果在batch Mode 下选中的容器改变了则为true
        private Boolean selectionContentChanged;

        internal SedionSelectionService(IDesignerHost host)
        {
            // 实例化滤过器
            setFilter();

            this.host = host;
            this.selectionsByComponent = new Hashtable();
            this.selectionChanged = false;
            this.batchMode = true;

            IComponentChangeService ccs = (IComponentChangeService)host.GetService(typeof(IComponentChangeService));
            Debug.Assert(ccs != null, "IComponentChangeService not found");
            if (ccs != null)
            {
                ccs.ComponentAdded += new ComponentEventHandler(ccs_ComponentAdded);
                ccs.ComponentRemoved += new ComponentEventHandler(ccs_ComponentRemoved);
                ccs.ComponentChanged += new ComponentChangedEventHandler(ccs_ComponentChanged);
            }

            host.TransactionOpened += new EventHandler(DesignerHost_TransactionOpened);
            host.TransactionClosed += new DesignerTransactionCloseEventHandler(DesignerHost_TransactionClosed);

            if (host.InTransaction)
                DesignerHost_TransactionOpened(host, EventArgs.Empty);

            host.LoadComplete += new EventHandler(DesignerHost_LoadComplete);
        }

        private static void setFilter()
        {
            if (filter == null)
                filter = new PropertyFilter();
        }

        private void ccs_ComponentChanged(object sender, ComponentChangedEventArgs e)
        {
            if (selectionsByComponent[e.Component] != null)
                OnSelectionContentsChanged();
        }

        /// <summary>
        ///  组件被移除时调用
        /// </summary>
        private void ccs_ComponentRemoved(object sender, ComponentEventArgs e)
        {
            SelectionItem sel = (SelectionItem)selectionsByComponent[e.Component];
            if (sel != null)
            {
                RemoveSelection(sel);

                // 如果移除了最后个组件,那么选中底层组件,如果不是,那么没关系
                if (selectionsByComponent.Count == 0 && host != null)
                {
                    // 遍历控件,选中zorder最大的那个组件
                    IComponent[] comps = new IComponent[host.Container.Components.Count];
                    host.Container.Components.CopyTo(comps, 0);

                    if (comps == null) return;

                    Int32 maxZOrder = -1;
                    Int32 defaultIndex = -1;
                    Object maxIndexComp = null;
                    Object baseComp = host.RootComponent;

                    if (baseComp == null) return;

                    for (int i = comps.Length - 1; i >= 0; i--)
                    {
                        if (comps[i] == baseComp)
                            continue;
                        else if (defaultIndex == -1)
                        {
                            defaultIndex = i;
                        }

                        if (comps[i] is Control)
                        {
                            Int32 zorder = ((Control)comps[i]).TabIndex;
                            if (zorder > maxZOrder)
                            {
                                maxZOrder = zorder;
                                maxIndexComp = (Object)comps[i];
                            }
                        }
                    }

                    // 选中zorder最大的组件
                    // 或者选中底层组件
                    if (maxIndexComp == null)
                    {
                        if (defaultIndex != -1)
                            maxIndexComp = comps[defaultIndex];
                        else
                            maxIndexComp = baseComp;
                    }

                    // 开始选中
                    ((ISelectionService)this).SetSelectedComponents(new Object[] { maxIndexComp }, SelectionTypes.Replace);
                }
                else
                {
                    OnSelectionChanged();
                }
            }
            else
            {
                OnSelectionContentsChanged();
            }
        }

        private void ccs_ComponentAdded(object sender, ComponentEventArgs e)
        {
            OnSelectionContentsChanged();
        }

        private void DesignerHost_TransactionClosed(object sender, DesignerTransactionCloseEventArgs e)
        {
            batchMode = false;
            FlushSelectionChanges();
        }

        private void DesignerHost_TransactionOpened(object sender, EventArgs e)
        {
            batchMode = true;
        }

        private void DesignerHost_LoadComplete(Object sender, EventArgs e)
        {
            batchMode = false;
            FlushSelectionChanges();
        }

        internal void SetPrimarySelection(SelectionItem sel)
        {
            if (sel != primarySelection)
            {
                if (primarySelection != null)
                    primarySelection.Primary = false;

                primarySelection = sel;
            }

            if (primarySelection != null)
                primarySelection.Primary = true;
        }

        private void RemoveSelection(SelectionItem sel)
        {
            selectionsByComponent.Remove(sel.Component);
            sel.Dispose();
        }

        private void AddSelection(SelectionItem sel)
        {
            selectionsByComponent[sel.Component] = sel;
        }

        /// <summary>
        ///  当可见性及batch模式改变时,调用该方法
        /// </summary>
        private void FlushSelectionChanges()
        {
            if (!batchMode)
            {
                if (selectionChanged) OnSelectionChanged();
                if (selectionContentChanged) OnSelectionContentsChanged();
            }
        }

        /// <summary>
        ///  当选中项发生改变时被调用,并触发change事件
        /// </summary>
        private void OnSelectionChanged()
        {
            if (batchMode)
                selectionChanged = true;
            else
            {
                selectionChanged = false;

                // 触发changing事件
                if (SelectionChanging != null)
                {
                    try
                    {
                        SelectionChanging(this, EventArgs.Empty);
                    }
                    catch (Exception)
                    {
                        Debug.Fail("Exception throw in selectionChanging event.");
                    }
                }

                // 触发changed事件
                if (SelectionChanged != null)
                {
                    try
                    {
                        SelectionChanged(this, EventArgs.Empty);
                    }
                    catch (Exception)
                    {
                        Debug.Fail("Exception thrown in selectionChanged event.");
                    }
                }

                OnSelectionContentsChanged();
            }
        }

        /// <summary>
        ///  当选中项被改变时,或者仅仅是容器选中项给改变时调用
        /// </summary>
        private void OnSelectionContentsChanged()
        {
            if (batchMode)
                selectionContentChanged = true;
            else
            {
                selectionContentChanged = false;

                PropertyGrid grid = ((PropertyGrid)host.GetService(typeof(PropertyGrid)));
                if (grid != null)
                {
                    ICollection col = ((ISelectionService)this).GetSelectedComponents();
                    Object[] selection = new Object[col.Count];
                    col.CopyTo(selection, 0);
                    Object cp = null;
                    if (col.Count > 0)
                        cp = filter.Filter(selection[0]);
                    grid.SelectedObject = cp;
                }
            }
        }

        internal void Dispose()
        {
            host.RemoveService(typeof(ISelectionService));
            host.TransactionOpened -= new EventHandler(this.DesignerHost_TransactionOpened);
            host.TransactionClosed -= new DesignerTransactionCloseEventHandler(this.DesignerHost_TransactionClosed);
            if (host.InTransaction)
                DesignerHost_TransactionClosed(host, new DesignerTransactionCloseEventArgs(true, true));

            host.LoadComplete -= new EventHandler(this.DesignerHost_LoadComplete);

            IComponentChangeService ccs = (IComponentChangeService)host.GetService(typeof(IComponentChangeService));
            if (ccs != null)
            {
                ccs.ComponentChanged -= new ComponentChangedEventHandler(ccs_ComponentChanged);
                ccs.ComponentAdded -= new ComponentEventHandler(ccs_ComponentAdded);
                ccs.ComponentRemoved -= new ComponentEventHandler(ccs_ComponentRemoved);
            }

            SelectionItem[] sels = new SelectionItem[selectionsByComponent.Values.Count];
            selectionsByComponent.Values.CopyTo(sels, 0);

            for (int i = 0; i < sels.Length; i++)
            {
                sels[i].Dispose();
            }

            selectionsByComponent.Clear();
            primarySelection = null;
        }

        #region ISelectionService 成员

        bool ISelectionService.GetComponentSelected(object component)
        {
            return (component != null && selectionsByComponent[component] != null);
        }

        /// <summary>
        ///  返回选中的组件对象集合
        /// </summary>
        System.Collections.ICollection ISelectionService.GetSelectedComponents()
        {
            Object[] sels = new Object[selectionsByComponent.Values.Count];
            selectionsByComponent.Values.CopyTo(sels, 0);
            Object[] objects = new Object[sels.Length];

            for (int i = 0; i < sels.Length; i++)
            {
                objects[i] = ((SelectionItem)sels[i]).Component;
            }

            return objects;
        }

        /// <summary>
        ///  主选择对象是最后选中的对象
        /// </summary>
        object ISelectionService.PrimarySelection
        {
            get
            {
                if (primarySelection == null)
                {
                    IDictionaryEnumerator selections = (IDictionaryEnumerator)selectionsByComponent.GetEnumerator();
                    Boolean valueFound = selections.MoveNext();

                    if (valueFound)
                    {
                        primarySelection = (SelectionItem)selections.Value;
                        primarySelection.Primary = true;
                    }
                }

                if (primarySelection != null)
                    return primarySelection.Component;

                return null;
            }
        }

        public event EventHandler SelectionChanged;
        public event EventHandler SelectionChanging;

        int ISelectionService.SelectionCount
        {
            get { return selectionsByComponent.Count; }
        }

        /// <summary>
        ///  选中给予的组件
        /// </summary>
        void ISelectionService.SetSelectedComponents(System.Collections.ICollection components, SelectionTypes selectionType)
        {
            Boolean fToggle = false;
            Boolean fControl = false;
            Boolean fClick = false;
            Boolean fChange = false;

            if (components == null)
                components = new Component[0];

            if ((selectionType & SelectionTypes.Auto) == SelectionTypes.Auto ||
                (selectionType & SelectionTypes.Primary) == SelectionTypes.Primary)
            {
                fControl = ((Control.ModifierKeys & Keys.Control) == Keys.Control);

                // 判断是否为组件键
                fToggle = ((Control.ModifierKeys & Keys.Control) != 0 ||
                    (Control.ModifierKeys & Keys.Shift) != 0 && components.Count == 1
                    && (selectionType & SelectionTypes.MouseUp) != SelectionTypes.MouseUp);
            }

            if ((selectionType & SelectionTypes.Primary) == SelectionTypes.Primary)
                fClick = true;

            if (!fToggle && !fControl)
            {
                Object firstSelction = null;
                foreach (Object o in components)
                {
                    firstSelction = o;
                    break;
                }

                if (fClick && components.Count == 1 && ((ISelectionService)this).GetComponentSelected(firstSelction))
                {
                    SelectionItem oldPrimary = primarySelection;
                    SetPrimarySelection((SelectionItem)selectionsByComponent[firstSelction]);
                    if (oldPrimary != primarySelection)
                        fChange = true;
                }
                else
                {
                    SelectionItem[] selections = new SelectionItem[selectionsByComponent.Values.Count];
                    selectionsByComponent.Values.CopyTo(selections, 0);

                    foreach (SelectionItem item in selections)
                    {
                        Boolean remove = true;
                        foreach (Object comp in components)
                        {
                            if (comp == item.Component)
                            {
                                remove = false;
                                break;
                            }
                        }

                        if (remove)
                        {
                            RemoveSelection(item);
                            fChange = true;
                        }
                    }
                }
            }

            SelectionItem primarySel = null;
            Int32 selectedCount = selectionsByComponent.Count;

            // 开始设置选中项
            foreach (Component comp in components)
            {
                if (comp != null)
                {
                    SelectionItem item = (SelectionItem)selectionsByComponent[comp];

                    if (item == null)
                    {
                        item = new SelectionItem(this, comp);
                        AddSelection(item);

                        if (fControl || fToggle)
                            primarySel = item;

                        fChange = true;
                    }
                    else
                    {
                        if (fToggle)
                        {
                            // 从选中的列表中移除
                            RemoveSelection(item);
                            fChange = true;
                        }
                    }
                }
            }

            if (primarySel != null)
                SetPrimarySelection(primarySel);

            // 通知选择项已经更改
            if (fChange)
                OnSelectionChanged();
        }

        void ISelectionService.SetSelectedComponents(System.Collections.ICollection components)
        {
            ((ISelectionService)this).SetSelectedComponents(components, SelectionTypes.Auto);
        }

        #endregion
    }
}
